import re
import os
import sublime


def get_max_width(*args):
    max_width = 0
    for arg in args:
        if len(str(arg)) > max_width:
            max_width = len(str(arg))
    return max_width


class ConstHelper:
    defConstPattern = r'(?<=INT8U const FAC_SET).+'
    maxConstPattern = r'(?<=INT8U const FUN_CODE_MAX).+'
    minConstPattern = r'(?<=INT8U const FUN_CODE_MIN).+'
    ADDRESS_ENUM = r'^\s+LOGIC_ADD(.*)[\s\S]+(?=,[\s\S]+FUN_CODE[\s\S]+})'

    def search_text(view, pattern):
        text = view.substr(sublime.Region(0, view.size()))
        pattern = re.compile(pattern, re.MULTILINE)
        return pattern.search(text)

    def getDatas(view, pattern):
        rowRegion = ConstHelper.getConstRegion(view, pattern)
        if not rowRegion:
            return

        rowStr = view.substr(rowRegion)

        findPattern = re.compile(r'(?<={).+?(?=})')
        result = findPattern.search(rowStr)
        if not result:
            return

        dataStr = rowStr[result.span()[0]: result.span()[1]].split(',')
        datas = []

        for data in dataStr:
            datas.append(data.strip())

        return datas

    @staticmethod
    def getDatasFromStr(s, pattern):
        pattern = re.compile(pattern, re.MULTILINE)
        result = pattern.search(s)

        rowStr = s[result.span()[0]: result.span()[1]]

        findPattern = re.compile(r'(?<={).+?(?=})')
        result = findPattern.search(rowStr)
        if not result:
            return

        dataStr = rowStr[result.span()[0]: result.span()[1]].split(',')
        datas = []

        for data in dataStr:
            datas.append(data.strip())

        return datas

    def getConstRegion(view, pattern):
        result = ConstHelper.search_text(view, pattern)
        if result is None:
            return

        return sublime.Region(result.span()[0], result.span()[1])

    def getCurrentFolder():
        folders = sublime.active_window().folders()
        if not folders:
            return
        return folders[0]

    def getLogicFilePath():
        folder = ConstHelper.getCurrentFolder()
        if not folder:
            return

        pattern = re.compile(r'logic\.c', re.I)
        for dirpath, dirnames, filenames in os.walk(folder):
            for filename in filenames:
                if pattern.search(filename):
                    return os.path.join(dirpath, filename)

    def getUserFilePath():
        folder = ConstHelper.getCurrentFolder()
        if not folder:
            return

        pattern = re.compile(r'user\.h', re.I)
        for dirpath, dirnames, filenames in os.walk(folder):
            for filename in filenames:
                if pattern.search(filename):
                    return os.path.join(dirpath, filename)

    def getConstsDatas(fileContent=None):
        if not fileContent:
            logicfilePath = ConstHelper.getLogicFilePath()
            if not logicfilePath:
                return

            fileContent = ''
            with open(logicfilePath) as file:
                fileContent = file.read()

        defDatas = ConstHelper.getDatasFromStr(
            fileContent, ConstHelper.defConstPattern)
        maxDatas = ConstHelper.getDatasFromStr(
            fileContent, ConstHelper.maxConstPattern)
        minDatas = ConstHelper.getDatasFromStr(
            fileContent, ConstHelper.minConstPattern)

        datas = []
        for i in range(len(defDatas)):
            datas.append((defDatas[i], maxDatas[i], minDatas[i]))

        return datas

    def convertFromDatas(datas):
        head = ['INT8U const FAC_SET[]      = {',
                'INT8U const FUN_CODE_MAX[] = {',
                'INT8U const FUN_CODE_MIN[] = {']

        defDatas = head[0]
        maxDatas = head[1]
        minDatas = head[2]
        for i in range(len(datas)):
            max_width = get_max_width(datas[i][0], datas[i][1], datas[i][2])
            if i < len(datas) - 1:
                defDatas = defDatas + ' ' * \
                    (max_width - len(str(datas[i][0]))) + datas[i][0] + ', '
                maxDatas = maxDatas + ' ' * \
                    (max_width - len(str(datas[i][1]))) + datas[i][1] + ', '
                minDatas = minDatas + ' ' * \
                    (max_width - len(str(datas[i][2]))) + datas[i][2] + ', '
            else:
                defDatas = defDatas + datas[i][0] + '};\n'
                maxDatas = maxDatas + datas[i][1] + '};\n'
                minDatas = minDatas + datas[i][2] + '};\n'

        return [defDatas, maxDatas, minDatas]

    def getAddressDatas():
        userFilePath = ConstHelper.getUserFilePath()
        if not userFilePath:
            print('没有找到user.h文件')
            return []

        fileContent = ''
        with open(userFilePath) as file:
            fileContent = file.read()

        pattern = re.compile(ConstHelper.ADDRESS_ENUM, re.MULTILINE)
        result = pattern.search(fileContent)

        # print(userFilePath)
        # print(fileContent)

        if not result:
            print('没有找到地址列表')
            return []

        originDataStr = fileContent[result.start(): result.end()].splitlines()

        addressList = []
        for line in originDataStr:
            if line.strip().find('//') == 0:
                continue

            pair = line.split(',')
            if len(pair) > 1:
                addressList.append((pair[0].strip('=0 '), pair[1].strip(' /')))
            else:
                addressList.append((pair[0].strip('=0 '), ''))

        return addressList

    def getConstsHtml():
        constDatas = ConstHelper.getConstsDatas()
        if not constDatas:
            return ''

        html = '<body>'
        for defData, maxData, minData in constDatas:
            html += defData + ', ' + maxData + ', ' + minData + '<br>'

        html += '</body>'
        print(html)
        return html

    def getConstList():
        constDatas = ConstHelper.getConstsDatas()
        if not constDatas:
            return []

        result = []
        for i, datas in enumerate(constDatas):
            result.append((datas[0] + ', ' + datas[1] + ', ' + datas[2], i))

        return result

    def removeVariable(fileContent, addressName):
        pattern = r'^#define.*' + addressName + r'.*\n'
        result = re.search(pattern, fileContent, re.M)

        if not result:
            return fileContent

        fileContent = fileContent[:result.start()] + \
            fileContent[result.end():]

        return fileContent

    def removeAddress(fileContent, addressName):
        pattern = r'^\W*' + addressName + r'.*\n'
        result = re.search(pattern, fileContent, re.M)

        if not result:
            return fileContent

        fileContent = fileContent[:result.start()] + \
            fileContent[result.end():]

        return fileContent

    def removeData(fileContent, address):
        datas = ConstHelper.getConstsDatas(fileContent)
        datas.pop(address)

        datasString = ConstHelper.convertFromDatas(datas)

        pattern = \
            r'INT8U const FAC_SET[\s\S]*?FUN_CODE_MAX[\s\S]*?FUN_CODE_MIN.*?\n'
        result = re.search(pattern, fileContent, re.M)

        if not result:
            return fileContent

        fileContent = fileContent[:result.start()] + \
            datasString[0] + datasString[1] + datasString[2] + \
            fileContent[result.end():]

        return fileContent

    def modifyData(data, address):
        logicfilePath = ConstHelper.getLogicFilePath()
        if not logicfilePath:
            return

        fileContent = ''
        with open(logicfilePath) as file:
            fileContent = file.read()

        datas = ConstHelper.getConstsDatas(fileContent)
        datas[address] = data

        datasString = ConstHelper.convertFromDatas(datas)

        pattern = \
            r'INT8U const FAC_SET[\s\S]*?FUN_CODE_MAX[\s\S]*?FUN_CODE_MIN.*?\n'
        result = re.search(pattern, fileContent, re.M)

        if not result:
            return fileContent

        fileContent = fileContent[:result.start()] + \
            datasString[0] + datasString[1] + datasString[2] + \
            fileContent[result.end():]

        with open(logicfilePath, 'w') as file:
            file.write(fileContent)

    def removeConst(address, addressName):
        userFilePath = ConstHelper.getUserFilePath()
        logicfilePath = ConstHelper.getLogicFilePath()

        if not userFilePath or not logicfilePath:
            return

        fileContent = ''
        with open(userFilePath) as file:
            fileContent = file.read()

        fileContent = ConstHelper.removeVariable(fileContent, addressName)
        fileContent = ConstHelper.removeAddress(fileContent, addressName)

        with open(userFilePath, 'w') as file:
            file.write(fileContent)

        with open(logicfilePath) as file:
            fileContent = file.read()

        fileContent = ConstHelper.removeData(fileContent, address)

        with open(logicfilePath, 'w') as file:
            file.write(fileContent)

    def getConstVariable(addressName, fileContent=None):
        if not fileContent:
            userFilePath = ConstHelper.getUserFilePath()

            if not userFilePath:
                return

            with open(userFilePath) as file:
                fileContent = file.read()

        pattern = r'(?<=define)\W*\w*\W*(?=\w*\[' + addressName + r'\])'
        result = re.search(pattern, fileContent, re.M)

        if not result:
            return

        return fileContent[result.start(): result.end()].strip()
